package com.iteaj.iboot.plugin.crawler.sites.buyin;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iteaj.iboot.plugin.crawler.entity.SiteContent;
import com.iteaj.iboot.plugin.crawler.entity.SiteContentMedia;
import com.iteaj.iboot.plugin.crawler.sites.FetchMediaParam;
import com.iteaj.iboot.plugin.crawler.sites.ResolverParam;
import com.iteaj.iboot.plugin.crawler.sites.SeleniumUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.stereotype.Component;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

@Component
public class BuyinResolver extends SpringSiteResolverSupport {

    private final static String SITE_NAME = "巨量百应";
    private final static Integer COLLECT_NUM = 12;
    private final static Integer COLLECT_VIDEO_NUM = 8;

    @Override
    public String getAlias() {
        return "buyin_cut";
    }

    @Override
    public void resolve(ResolverParam param) {
        String url = param.getUrl();
        JSONObject content = param.getContent();
        if(content.getInteger("code") == 0) {
            JSONObject data = content.getJSONObject("data");
            // 采集数据列表
            if(url.contains("common/material_list")) {
                resolverMaterialList(param, data);
            } else if(url.contains("decision/pack_detail")) { // 内容详情
                resolverPackDetail(data);
            } else if(url.contains("decision/extract_copywriting")) {
                resolverCopywriting(data);
            }
        } else {
            logger.error("<<< 获取数据失败 原因: {} - url: {}", content.getString("msg"), url);
        }
    }

    private void resolverCopywriting(JSONObject data) {
        JSONArray jsonArray = data.getJSONArray("content_text");
        StringBuilder stringBuilder = new StringBuilder();
        if(CollectionUtil.isNotEmpty(jsonArray)) {
            String contentId = data.getString("content_id");
            logger.info("<<< 开始解析视频内容文本 内容id: {}", contentId);
            jsonArray.forEach(item -> {
                stringBuilder.append(((JSONObject)item).getString("text"));
            });

            siteContentService.updateMediaContent(contentId, stringBuilder.toString());
        }
    }

    private void resolverMaterialList(ResolverParam param, JSONObject data) {
        JSONArray jsonArray = data.getJSONArray("promotions");
        if(CollectionUtil.isNotEmpty(jsonArray)) {
            logger.info("<<< 开始解析商品列表 记录数: {}", jsonArray.size());
            List<SiteContent> contents = new ArrayList<>();

            for (int i = 0; i < jsonArray.size(); i++) {
                if(i == COLLECT_NUM) break;

                JSONObject itemObject = (JSONObject)jsonArray.get(i);
                JSONObject baseInfo = itemObject.getJSONObject("base_info");
                JSONObject priceInfo = itemObject.getJSONObject("price_info");
                JSONObject cosInfo = itemObject.getJSONObject("cos_info");
                String promotionId = itemObject.getString("promotion_id");

                siteContentService.getByPromotionId(promotionId).ifNotPresent(result -> {
                    SiteContent siteContent = new SiteContent()
                            .setStatus(SiteContent.STATUS[0])
                            .setAlias("shop").setType("video") // 购物 视频剪辑
                            .setCosFee(cosInfo.getDouble("cos_fee") / 100)
                            .setCosRate(cosInfo.getDouble("cos_ratio"))
                            .setPriceText(priceInfo.getString("price_text"))
                            .setSitesId(getSites().getId()).setContentId(promotionId)
                            .setPrice(priceInfo.getBigDecimal("price").divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN))
                            .setTitle(baseInfo.getString("title")).setCoverUrl(baseInfo.getString("cover"))
                            .setImages(baseInfo.getJSONArray("images"));
                    contents.add(siteContent);
                });
            }

            if(CollectionUtil.isNotEmpty(contents)) {
                contents.forEach(item -> siteContentService.save(item));
                contents.stream().filter(content -> content.getImages() != null).forEach(content -> {
                    JSON images = content.getImages();
                    if (images instanceof JSONArray) {
                        List<SiteContentMedia> list = ((JSONArray) images).stream().map(item ->
                                new SiteContentMedia().setSiteContentId(content.getId())
                                        .setUrl(item.toString())
                                        .setTitle(content.getTitle())
                                        .setSales(0).setType("image")
                                        .setOriMediaId(content.getContentId())
                                        .setContent(content.getContent())
                                        .setStatus(SiteContentMedia.STATUS[0])
                                        .setOrderConversionRate(0.0))
                        .toList();

                        siteContentService.saveMedias(list);
                    }
                });
            }
        }
    }

    private void resolverPackDetail(JSONObject data) {
        JSONObject model = data.getJSONObject("model");
        if(CollectionUtil.isNotEmpty(model)) {
            JSONObject saleContentData = model.getJSONObject("sale_content_data");
            // 带货内容
            if(CollectionUtil.isNotEmpty(saleContentData) && saleContentData.getInteger("code") == 0) {
                String promotionId = data.getString("promotion_id");
                logger.info("<<< 开始解析内容详情 内容id: {}", promotionId);
                siteContentService.getByPromotionId(promotionId).ifPresent(siteContent -> {
                    JSONArray contentList = saleContentData.getJSONArray("content_list");
                    if(CollectionUtil.isNotEmpty(contentList)) {
                        JSONObject firstContent = (JSONObject) contentList.get(0);
                        String contentType = firstContent.getString("content_type");

                        // 只保存视频和图文
                        if(contentType.equals("video") || contentType.equals("image_text")) {
                            List<SiteContentMedia> list = new ArrayList<>();
                            for (Object o : contentList) {
                                if(contentType.equals("video")) {
                                    if (list.size() == COLLECT_VIDEO_NUM) {
                                        break;
                                    }
                                } else {
                                    if (list.size() == 12) {
                                        break;
                                    }
                                }

                                JSONObject itemValue = (JSONObject) o;
                                String contentId = itemValue.getString("content_id");
                                JSONArray imgList = itemValue.getJSONArray("img_list");
                                JSONObject mediaInfo = itemValue.getJSONObject("media_info");
                                String contentTitle = itemValue.getString("content_title");
                                String coverUrl, videoUrl; Integer duration = null;
                                if (mediaInfo != null) {
                                    coverUrl = mediaInfo.getString("cover_url");
                                    videoUrl = mediaInfo.getString("video_url");
                                    duration = mediaInfo.getInteger("duration") / 1000;

                                    list.add(new SiteContentMedia()
                                            .setTitle(contentTitle).setOriMediaId(contentId)
                                            .setType("video").setDuration(duration)
                                            .setCoverUrl(coverUrl).setUrl(videoUrl)
                                            .setSiteContentId(siteContent.getId())
                                            .setSales(itemValue.getInteger("sales"))
                                            .setPlayCount(itemValue.getInteger("play_count"))
                                            .setOrderConversionRate(itemValue.getDouble("order_conversion_rate")));
                                } else {
                                    coverUrl = itemValue.getString("content_cover");
                                    if(CollectionUtil.isNotEmpty(imgList)) {
                                        for (Object object : imgList) {
                                            list.add(new SiteContentMedia()
                                                    .setTitle(contentTitle).setOriMediaId(contentId)
                                                    .setType("image").setDuration(duration)
                                                    .setCoverUrl(coverUrl)
                                                    .setUrl(object.toString())
                                                    .setSiteContentId(siteContent.getId())
                                                    .setSales(itemValue.getInteger("sales"))
                                                    .setPlayCount(itemValue.getInteger("play_count"))
                                                    .setOrderConversionRate(itemValue.getDouble("order_conversion_rate")));
                                        }
                                    }
                                }

                            }

                            if(CollectionUtil.isNotEmpty(list)) {

                                List<SiteContentMedia> productList = siteContentService.listMediasByContentId(siteContent.getId());

                                siteContentService.saveMedias(list);

                                List<SiteContentMedia> images = list.stream()
                                        .filter(item -> item.getType().equals("image"))
                                        .toList();

                                List<SiteContentMedia> videos = list.stream()
                                        .filter(item -> item.getType().equals("video"))
                                        .toList();

                                fetchMedia(new FetchMediaParam(promotionId, images, videos, productList));
                            }
                        } else {

                        }

                    } else if(siteContent.getImages() instanceof JSONArray) {
                        // 没有任何可用媒体信息直接删除此记录
                        if(((JSONArray) siteContent.getImages()).isEmpty()) {
                            siteContentService.removeById(siteContent.getId()); return;
                        }
                    }

                    // 更新处理状态
                    siteContentService.updateStatus(promotionId, SiteContent.STATUS[1]);
                });
            }
        }
    }

    @Override
    public void run() {
        ChromeDriver driver = null;
        try {
            URL resource = getClass().getClassLoader().getResource("chromedriver.exe");
            File file = new File(resource.getFile());
            Logger.getLogger("org.openqa.selenium.chrome").setLevel(Level.ALL);

            ChromeOptions options = new ChromeOptions();
            options.setExperimentalOption("debuggerAddress", "127.0.0.1:9333");
//            options.setBinary("D:\\软件\\chrome-win64\\chrome.exe");
//            options.setPageLoadStrategy(PageLoadStrategy.NONE);
//            options.addArguments("--disable-infobars"); // 去掉信息栏
//            options.addArguments("--user-data-dir="+dataDir);
//            options.addArguments("--no-sandbox");
//            options.addArguments("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36");
//            options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"}); // 去掉被控制的提示
            File extension = new File("D:\\Program Data\\web\\extension\\test.crx");
            options.addExtensions(extension);
            ChromeDriverService driverService = new ChromeDriverService.Builder()
                    .usingDriverExecutable(file).build();
            ChromeDriver finalDriver = driver = new ChromeDriver(driverService, options);

            driver.manage().window().maximize();
            driver.get("https://buyin.jinritemai.com/mpa/account/login?log_out=1&type=24");
            seleniumProcessInfoLog(SITE_NAME, "打开登录页", "https://buyin.jinritemai.com/mpa/account/login?log_out=1&type=24");
            driver.manage().addCookie(new Cookie("crw_id", getSites().getId().toString()));
            driver.manage().addCookie(new Cookie("crw_alias", getSites().getAlias()));

            // 等待登录成功
            seleniumProcessInfoLog(SITE_NAME, "等待用户登录", "以此链接开头 https://buyin.jinritemai.com/dashboard");
            while (true) {
                Object o = driver.executeScript("return location.href");
                if(o != null && o.toString().startsWith("https://buyin.jinritemai.com/dashboard")) {
    //                driver.navigate().to("https://buyin.jinritemai.com/dashboard/merch-picking-library");
                    seleniumProcessInfoLog(SITE_NAME, "登录成功", "登录成功即将跳到选品广场");
                    break;
                }

                SeleniumUtils.waitByTimes(1000, false);
            }

            SeleniumUtils.waitByTimes(1200, 2600);

            // 跳到选品广场
            WebDriverWait xuanPingWait = new WebDriverWait(driver, Duration.ofSeconds(10));
            WebElement xuanPingElement = xuanPingWait.until(ExpectedConditions.presenceOfElementLocated(By
                    .cssSelector(".auxo-menu-root.headerNav.newHeaderNav li:nth-child(3)")));
            if(xuanPingElement != null) {
//                WebElement element = xuanPingElement.findElement(By.cssSelector(".headerNav__submenu-column-wrapper"));
                seleniumProcessInfoLog(SITE_NAME, "点击选品广场", "进入选品页面");
                xuanPingElement.click();

                Actions actions = new Actions(driver);
                seleniumProcessInfoLog(SITE_NAME, "在选品页面移动鼠标", "防止选品页面的弹框阻止页面采集");
                actions.moveByOffset(0, 0).perform();
                SeleniumUtils.waitByTimes(300, 1000);

                // 点击搜索框
                WebDriverWait searchWait = new WebDriverWait(driver, Duration.ofSeconds(10));
                WebElement searchElement = searchWait.until(ExpectedConditions.presenceOfElementLocated(By.id("SearchBarWrapper")));
                if(searchElement != null) {
                    seleniumProcessInfoLog(SITE_NAME, "点击选品页面搜索框", "做选品搜索");
                    searchElement.click();
//                    driver.findElement(By.cssSelector(".searchInput__button")).click();
                }
            } else {
                System.out.println("<<< 获取不到选品选项");
                return;
            }

            String listWindowHandle = driver.getWindowHandle();

            // 等待产品列表加载完成
            WebElement element = null;
            for (int i = 0; i < 3; i++) {
                try {
                    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
                    element = wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".auxo-sp-infinit-container div")));
                    if(element != null || i==2) {
                        seleniumProcessInfoLog(SITE_NAME, "选品页面数据加载完成", "必须等待数据完成才能进行下面的操作");
                        break;
                    }
                } catch (Exception e) {

                }
            }

            if(element == null) {
                seleniumProcessWarnLog(SITE_NAME, "获取元素失败退出采集", "失败元素选择器(.auxo-sp-infinit-container div)");
                return;
            }

            SeleniumUtils.waitByTimes(1000, false);
            // 获取所有产品
            seleniumProcessInfoLog(SITE_NAME, "获取所有产品元素", "产品元素选择器(./child::*)");
            List<WebElement> elements = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                elements = element.findElements(By.xpath("./child::*"));
                if(elements.size() >1) {
                    break;
                }

                if(elements.size() == 1 && Objects.requireNonNull(elements.get(0).getAttribute("class")).contains("index_module__card")) {
                    break;
                }

                SeleniumUtils.waitByTimes(1000, false);
            }

            seleniumProcessInfoLog(SITE_NAME, "获取到的产品元素数量("+elements.size()+")", "产品列表");

            for (int i = 0; i < elements.size(); i++) {
                if(i == COLLECT_NUM) {
                    break;
                }

                WebElement item = elements.get(i);
                try {
                    // 采集每个产品数据
                    String aClass = item.getAttribute("class");
                    if(aClass != null && !aClass.contains("index_module__blank") && aClass.contains("index_module__card")) {
                        item.click(); // 打开产品详情页
                        Set<String> windowHandles = finalDriver.getWindowHandles();
                        for (String window : windowHandles) {
                            if(!window.equals(finalDriver.getWindowHandle())) {
                                finalDriver.switchTo().window(window);
                                if(finalDriver.getCurrentUrl().contains("merch-picking-library/merch-promoting")) {
                                    WebDriverWait wait = new WebDriverWait(finalDriver, Duration.ofSeconds(30));
                                    WebElement contentEle = wait.until(ExpectedConditions.presenceOfElementLocated(By
                                            .xpath("//*[@id=\"app\"]/div/div/div[2]/div[2]/div/div[1]/div[1]/div/div[2]")));
                                    if(contentEle != null) {
                                        contentEle.click(); // 点击带货内容标签
                                    }

                                    try {
                                        // 点击提取文案
                                        WebDriverWait waitText = new WebDriverWait(finalDriver, Duration.ofSeconds(30));
                                        WebElement contentTextEle = waitText.until(ExpectedConditions.presenceOfElementLocated(By
                                                .xpath("//*[@id=\"rc-tabs-0-panel-content\"]/div/div[2]/div[2]/div/div/div")));
                                        if(contentTextEle != null) {
                                            SeleniumUtils.waitByTimes(3000, false);

                                            // 获取所有视频节点
                                            List<WebElement> eleElements = contentTextEle.findElements(By.xpath("./child::*"));
                                            if(eleElements.size() > 1) {
                                                for (int i1 = 0; i1 < eleElements.size(); i1++) {
                                                    if(i1 == COLLECT_VIDEO_NUM) break; // 只采集8条

                                                    WebElement textCopy = eleElements.get(i1);
                                                    WebElement copyElement = textCopy.findElement(By.xpath("./div/div[3]/div[1]"));
                                                    SeleniumUtils.waitByTimes(2000, 3000);
                                                    copyElement.click(); // 点击提取文案

                                                    try {
                                                        // 等待文案弹窗
                                                        WebDriverWait waitCancel = new WebDriverWait(finalDriver, Duration.ofSeconds(10));
                                                        WebElement contentCancelEle = waitCancel.until(ExpectedConditions.presenceOfElementLocated(By
                                                                .cssSelector("[elementtiming='daren-element-timing'] .auxo-modal-footer > button:nth-child(2)")));

                                                        // 点击取消按钮
                                                        if(contentCancelEle != null) {
                                                            SeleniumUtils.waitByTimes(1500, 2800);
                                                            contentCancelEle.click();
                                                        }
                                                    } catch (Exception e) {
                                                        e.printStackTrace();
                                                    }
                                                }
                                            }

                                        }
                                    } catch (Exception e) {
                                        logger.error("<<< 提取文案失败({}) {}", SITE_NAME, "退出当前记录文案采集", e);
                                    }
                                    try {
                                        WebElement imageText = finalDriver.findElement(By.id("rc-tabs-1-tab-image_text"));
                                        imageText.click();

                                        Thread.sleep(RandomUtil.randomLong(5000, 9000));
                                        seleniumProcessInfoLog(SITE_NAME, "关闭当前详情页面", "当前详情页采集完成, 继续下一个产品采集");
                                        finalDriver.close(); // 关闭当前标签
                                        finalDriver.switchTo().window(listWindowHandle); // 跳到列表页面
                                    } catch (InterruptedException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                            }
                        }

                    } else {
                        String style = element.getAttribute("class");
                        seleniumProcessWarnLog(SITE_NAME, "此产品元素的class值异常", "期待包含[index_module__card]实际为: " + aClass + "; 父级class=" + style);
//                        Object o = driver.executeScript("return window.crawlerInfo.urls");
//                        System.out.println(o);
//                        Object userAgent = driver.executeScript("return navigator.userAgent");
//                        System.out.println(userAgent);
                    }
                } catch (RuntimeException e) {
                    e.printStackTrace();
                }
            }

            driver.quit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(driver != null) {
                driver.quit();
                seleniumProcessInfoLog(SITE_NAME, "采集完成退出", "此处采集完成不代表采集成功");
            }
        }
    }
}
